﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Web.UI;

namespace HeroldIT.Dnn.JQuery.UI
{
    /// <summary>
    /// Creates a jQuery UI Dialog widget.
    /// </summary>
    [ParseChildren(true)]
    public class Dialog : Control
    {
        #region properties

        /// <summary>
        /// Gets or sets the name of the theme to use for the control.
        /// </summary>
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Appearance")]
        public string ThemeName { get; set; }

        /// <summary>
        /// Gets the content control collection of the dialog.
        /// </summary>
        public ControlCollection Content
        {
            get { return this.Controls; }
        }

        #endregion

        #region jQuery UI settings properties

        private bool autoOpen = true;

        /// <summary>
        /// Gets or sets whether the dialog will open automatically when the page loads.
        /// If <c>false</c> it will stay hidden until a client event opens it.
        /// </summary>
        [Setting("autoOpen")]
        [Browsable(true)]
        [Localizable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        [DefaultValue(true)]
        public bool AutoOpen
        {
            get { return this.autoOpen; }
            set { this.autoOpen = value; }
        }

        /// <summary>
        /// Gets or sets whether the bgiframe plugin will be used, to fix the issue in IE6
        /// where select boxes show on top of other elements, regardless of zIndex. Requires
        /// including the bgiframe plugin. Future versions may not require a separate plugin.
        /// </summary>
        [Setting("bgiframe")]
        [Browsable(true)]
        [Localizable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Appearance")]
        [DefaultValue(false)]
        public bool BGIframe { get; set; }

        private readonly IDictionary<string, string> buttons = new DialogButtons();

        /// <summary>
        /// Gets a collection of buttons that should be displayed on the dialog. The
        /// dictionary key is the text of the button. The value is the callback function
        /// for when the button is clicked. The context of the callback is the dialog
        /// element; if you need access to the button, it is available as the target
        /// of the event object.
        /// </summary>
        [Setting("buttons")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        public IDictionary<string, string> Buttons
        {
            get { return this.buttons; }
        }

        private bool closeOnEscape = true;

        /// <summary>
        /// Gets or sets whether the dialog should close when it has focus and the user
        /// presses the esacpe (ESC) key.
        /// </summary>
        [Setting("closeOnEscape")]
        [Browsable(true)]
        [Localizable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        [DefaultValue(true)]
        public bool CloseOnEscape
        {
            get { return this.closeOnEscape; }
            set { this.closeOnEscape = value; }
        }

        /// <summary>
        /// Gets or sets class name(s) that will be added to the dialog, for additional theming.
        /// </summary>
        [Setting("dialogClass")]
        [Browsable(true)]
        [Localizable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Appearance")]
        public string CssClass
        {
            get; set;
        }

        private bool draggable = true;

        /// <summary>
        /// Gets or sets whether the dialog will be draggable by the titlebar.
        /// </summary>
        [Setting("draggable")]
        [Browsable(true)]
        [Localizable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        [DefaultValue(true)]
        public bool Draggable
        {
            get { return this.draggable; }
            set { this.draggable = value; }
        }

        /// <summary>
        /// Gets or sets the height of the dialog, in pixels. The default is <c>0</c>,
        /// meaning the dialog will size itself automatically.
        /// </summary>
        [Setting("height")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Appearance")]
        [DefaultValue(0)]
        public int Height { get; set; }

        /// <summary>
        /// Gets or sets the effect to be used when the dialog is closed.
        /// </summary>
        [Setting("hide")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        public string Hide { get; set; }

        /// <summary>
        /// Gets or sets the maximum height to which the dialog can be resized, in pixels.
        /// The default is <c>0</c>, meaning no maximum.
        /// </summary>
        [Setting("maxHeight")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        [DefaultValue(0)]
        public int MaxHeight { get; set; }

        /// <summary>
        /// Gets or sets the maximum width to which the dialog can be resized, in pixels.
        /// The default is <c>0</c>, meaning no maximum.
        /// </summary>
        [Setting("maxWidth")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        [DefaultValue(0)]
        public int MaxWidth { get; set; }

        private int minHeight = 150;

        /// <summary>
        /// Gets or sets the minimum height to which the dialog can be resized, in pixels.
        /// </summary>
        [Setting("minHeight")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        [DefaultValue(150)]
        public int MinHeight
        {
            get { return this.minHeight; }
            set { this.minHeight = value; }
        }

        private int minWidth = 150;

        /// <summary>
        /// Gets or sets the minimum width to which the dialog can be resized, in pixels.
        /// </summary>
        [Setting("minWidth")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        [DefaultValue(150)]
        public int MinWidth
        {
            get { return this.minWidth; }
            set { this.minWidth = value; }
        }

        /// <summary>
        /// Gets or sets whether the dialog will have modal behavior; other items on the
        /// page will be disabled (i.e. cannot be interacted with). Modal dialogs create
        /// an overlay below the dialog but above other page elements.
        /// </summary>
        [Setting("modal")]
        [Browsable(true)]
        [Localizable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        [DefaultValue(false)]
        public bool IsModal { get; set; }

        private DialogPosition position = DialogPosition.Center;

        /// <summary>
        /// Gets or sets where the dialog should be displayed. If set to
        /// <see cref="DialogPosition.Custom"/>, you can use the
        /// <see cref="CustomPosition"/> property to specify coordinates or names for the
        /// position.
        /// </summary>
        [Setting("position")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Appearance")]
        [DefaultValue(DialogPosition.Center)]
        public DialogPosition Position
        {
            get { return this.position; }
            set { this.position = value; }
        }

        /// <summary>
        /// Gets or sets where the dialog should be displayed, if the <see cref="Position"/>
        /// property is set to <see cref="DialogPosition.Custom"/>.
        /// </summary>
        public DialogCustomPosition CustomPosition { get; set; }

        private bool resizable = true;

        /// <summary>
        /// Gets or sets whether the dialog will be resizeable.
        /// </summary>
        [Setting("resizable")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        [DefaultValue(true)]
        public bool Resizable
        {
            get { return this.resizable; }
            set { this.resizable = value; }
        }

        /// <summary>
        /// Gets or sets the effect to be used when the dialog is opened.
        /// </summary>
        [Setting("show")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        public string Show { get; set; }

        private bool stack = true;

        /// <summary>
        /// Gets or sets whether the dialog will stack on top of other dialogs.
        /// This will cause the dialog to move to the front of other dialogs when
        /// it gains focus.
        /// </summary>
        [Setting("stack")]
        [Browsable(true)]
        [Localizable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        [DefaultValue(true)]
        public bool Stack
        {
            get { return this.stack; }
            set { this.stack = value; }
        }

        /// <summary>
        /// Gets or sets the title of the dialog.
        /// </summary>
        [Setting("title")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Appearance")]
        public string Title { get; set; }

        private int width = 300;

        /// <summary>
        /// Gets or sets the width of the dialog, in pixels.
        /// </summary>
        [Setting("width")]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Appearance")]
        [DefaultValue(300)]
        public int Width
        {
            get { return this.width; }
            set { this.width = value; }
        }

        private int zIndex = 1000;

        /// <summary>
        /// Gets or sets the z-index to apply to the Dialog.
        /// </summary>
        [Setting("zIndex")]
        [Browsable(true)]
        [Localizable(false)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Appearance")]
        [DefaultValue(1000)]
        public int ZIndex
        {
            get { return this.zIndex; }
            set { this.zIndex = value; }
        }

        #endregion

        #region jQuery client events

        /// <summary>
        /// Defines the client events for the <see cref="Dialog"/> control.
        /// </summary>
        public sealed class ClientEventDefinitions
        {
            #region properties

            [Setting("beforeClose")]
            internal ClientEventHandler BeforeCloseHandler
            {
                get { return this.BeforeClose == null ? null : new ClientEventHandler("event,ui", this.BeforeClose); }
            }

            /// <summary>
            /// Gets or sets a javascript snippet, that is triggered when a dialog attempts to close.
            /// If the beforeclose event handler returns false, the close will be
            /// prevented. The names of the arguments to the function are <c>event</c> and <c>ui</c>.
            /// </summary>
            [Browsable(true)]
            [Localizable(false)]
            [EditorBrowsable(EditorBrowsableState.Always)]
            [Category("Behavior")]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public string BeforeClose
            {
                get;
                set;
            }

            [Setting("close")]
            internal ClientEventHandler CloseHandler
            {
                get
                {
                    return this.Close == null ? null : new ClientEventHandler("event,ui", this.Close);
                }
            }

            /// <summary>
            /// Gets or sets a javascript snippet, that is triggered when dialog is closed.
            /// The name of the arguments to the function are <c>event</c> and <c>ui</c>.
            /// </summary>
            [Browsable(true)]
            [Localizable(false)]
            [EditorBrowsable(EditorBrowsableState.Always)]
            [Category("Behavior")]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public string Close
            {
                get;
                set;
            }

            [Setting("drag")]
            internal ClientEventHandler DragHandler
            {
                get
                {
                    return this.Drag == null ? null : new ClientEventHandler("event,ui", this.Drag);
                }
            }

            /// <summary>
            /// Gets or sets a javascript snippet, that is triggered when the dialog is dragged. The
            /// names of the arguments to the function are <c>event</c> and <c>ui</c>.
            /// </summary>
            [Browsable(true)]
            [Localizable(false)]
            [EditorBrowsable(EditorBrowsableState.Always)]
            [Category("Behavior")]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public string Drag
            {
                get;
                set;
            }

            [Setting("dragStart")]
            internal ClientEventHandler DragStartHandler
            {
                get
                {
                    return this.DragStart == null ? null : new ClientEventHandler("event,ui", this.DragStart);
                }
            }

            /// <summary>
            /// Gets or sets a javascript snippet, that is triggered at the beginning of the
            /// dialog being dragged. The names of the arguments to the function are
            /// <c>event</c> and <c>ui</c> respectively.
            /// </summary>
            [Browsable(true)]
            [Localizable(false)]
            [EditorBrowsable(EditorBrowsableState.Always)]
            [Category("Behavior")]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public string DragStart
            {
                get;
                set;
            }

            [Setting("dragStop")]
            internal ClientEventHandler DragStopHandler
            {
                get
                {
                    return this.DragStop == null ? null : new ClientEventHandler("event,ui", this.DragStop);
                }
            }

            /// <summary>
            /// Gets or sets a javascript snippet, that is triggered after the dialog
            /// has been dragged. The names of the arguments to the function are
            /// <c>event</c> and <c>ui</c> respectively.
            /// </summary>
            [Browsable(true)]
            [Localizable(false)]
            [EditorBrowsable(EditorBrowsableState.Always)]
            [Category("Behavior")]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public string DragStop
            {
                get;
                set;
            }

            [Setting("focus")]
            internal ClientEventHandler FocusHandler
            {
                get
                {
                    return this.Focus == null ? null : new ClientEventHandler("event,ui", this.Focus);
                }
            }

            /// <summary>
            /// Gets or sets a javascript snippet, that is triggered when the dialog gains
            /// focus. The names of the arguments to the function are <c>event</c> and
            /// <c>ui</c>.
            /// </summary>
            [Browsable(true)]
            [Localizable(false)]
            [EditorBrowsable(EditorBrowsableState.Always)]
            [Category("Behavior")]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public string Focus
            {
                get;
                set;
            }

            [Setting("open")]
            internal ClientEventHandler OpenHandler
            {
                get
                {
                    return this.Open == null ? null : new ClientEventHandler("event,ui", this.Open);
                }
            }

            /// <summary>
            /// Gets or sets a javascript snippet, that is triggered when dialog is opened.
            /// The name of the arguments to the function are <c>event</c> and <c>ui</c>.
            /// </summary>
            [Browsable(true)]
            [Localizable(false)]
            [EditorBrowsable(EditorBrowsableState.Always)]
            [Category("Behavior")]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public string Open
            {
                get;
                set;
            }

            [Setting("resize")]
            internal ClientEventHandler ResizeHandler
            {
                get
                {
                    return this.Resize == null ? null : new ClientEventHandler("event,ui", this.Resize);
                }
            }

            /// <summary>
            /// Gets or sets a javascript snippet, that is triggered when the dialog is resized. The
            /// names of the arguments to the function are <c>event</c> and <c>ui</c>.
            /// </summary>
            [Browsable(true)]
            [Localizable(false)]
            [EditorBrowsable(EditorBrowsableState.Always)]
            [Category("Behavior")]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public string Resize
            {
                get;
                set;
            }

            [Setting("resizeStart")]
            internal ClientEventHandler ResizeStartHandler
            {
                get
                {
                    return this.ResizeStart == null ? null : new ClientEventHandler("event,ui", this.ResizeStart);
                }
            }

            /// <summary>
            /// Gets or sets a javascript snippet, that is triggered at the beginning of the
            /// dialog being resized. The names of the arguments to the function are
            /// <c>event</c> and <c>ui</c> respectively.
            /// </summary>
            [Browsable(true)]
            [Localizable(false)]
            [EditorBrowsable(EditorBrowsableState.Always)]
            [Category("Behavior")]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public string ResizeStart
            {
                get;
                set;
            }

            [Setting("resizeStop")]
            internal ClientEventHandler ResizeStopHandler
            {
                get
                {
                    return this.ResizeStop == null ? null : new ClientEventHandler("event,ui", this.ResizeStop);
                }
            }

            /// <summary>
            /// Gets or sets a javascript snippet, that is triggered after the dialog
            /// has been resized. The names of the arguments to the function are
            /// <c>event</c> and <c>ui</c> respectively.
            /// </summary>
            [Browsable(true)]
            [Localizable(false)]
            [EditorBrowsable(EditorBrowsableState.Always)]
            [Category("Behavior")]
            [PersistenceMode(PersistenceMode.InnerProperty)]
            public string ResizeStop
            {
                get;
                set;
            }

            #endregion

            #region constructors

            /// <summary>
            /// Creates a new <see cref="ClientEventDefinitions"/> instance.
            /// </summary>
            internal ClientEventDefinitions()
            {
            }

            #endregion
        }

        private readonly ClientEventDefinitions clientEvents = new ClientEventDefinitions();

        /// <summary>
        /// Holds the definitions for the client events.
        /// </summary>
        [SettingGroup]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        [Browsable(true)]
        [Localizable(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Behavior")]
        public ClientEventDefinitions ClientEvents
        {
            get
            {
                return this.clientEvents;
            }
        }

        #endregion

        #region jQuery client methods

        /// <summary>
        /// Defines the client methods for the <see cref="Dialog"/> control.
        /// </summary>
        public class ClientMethodDefinitions
        {
            #region fields

            private readonly Dialog owner;

            #endregion

            #region constructors

            internal ClientMethodDefinitions(Dialog owner)
            {
                this.owner = owner;
            }

            #endregion

            #region methods

            private string GenerateMethodCall(string methodName)
            {
                return String.Format(CultureInfo.InvariantCulture, "jQuery('#{0}').dialog('{1}')",
                                     this.owner.ClientID, methodName);
            }

            /// <summary>
            /// Gets a javascript snippet for the client close method.
            /// </summary>
            /// <returns>A javascript snippet for the client close method.</returns>
            public string Close()
            {
                return this.GenerateMethodCall("close");
            }

            /// <summary>
            /// Gets a javascript snippet for the client destroy method.
            /// </summary>
            /// <returns>A javascript snippet for the client destroy method.</returns>
            public string Destroy()
            {
                return this.GenerateMethodCall("destroy");
            }

            /// <summary>
            /// Gets a javascript snippet for the client disable method.
            /// </summary>
            /// <returns>A javascript snippet for the client disable method.</returns>
            public string Disable()
            {
                return this.GenerateMethodCall("disable");
            }

            /// <summary>
            /// Gets a javascript snippet for the client enable method.
            /// </summary>
            /// <returns>A javascript snippet for the client enable method.</returns>
            public string Enable()
            {
                return this.GenerateMethodCall("enable");
            }

            /// <summary>
            /// Gets a javascript snippet for the client isOpen method.
            /// </summary>
            /// <returns>A javascript snippet for the client isOpen method.</returns>
            public string IsOpen()
            {
                return this.GenerateMethodCall("isOpen");
            }

            /// <summary>
            /// Gets a javascript snippet for the client moveToTop method.
            /// </summary>
            /// <returns>A javascript snippet for the client moveToTop method.</returns>
            public string MoveToTop()
            {
                return this.GenerateMethodCall("moveToTop");
            }

            /// <summary>
            /// Gets a javascript snippet for the client open method.
            /// </summary>
            /// <returns>A javascript snippet for the client open method.</returns>
            public string Open()
            {
                return this.GenerateMethodCall("open");
            }

            #endregion
        }

        private ClientMethodDefinitions clientMethods;

        /// <summary>
        /// Gets a factory for creating javascript snippets for the <see cref="Dialog"/>'s
        /// client methods for use in event handlers.
        /// </summary>
        public ClientMethodDefinitions ClientMethods
        {
            get
            {
                if (null == this.clientMethods)
                {
                    this.clientMethods = new ClientMethodDefinitions(this);
                }
                return this.clientMethods;
            }
        }

        #endregion

        #region events

        /// <summary>
        /// This event is raised, just before the control applies its javascript
        /// settings to the initialization code. You can use it to manipulate the
        /// settings dictionary.
        /// </summary>
        /// <remarks>
        /// Be careful when using this event. It allows you to reach deeply into
        /// the internal workings of the control, possibly breaking functionality.
        /// </remarks>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        [Localizable(false)]
        [Category("Behavior")]
        public event EventHandler<SettingsEventArgs> ApplyingSettings;

        /// <summary>
        /// Fires the <see cref="ApplyingSettings"/> event.
        /// </summary>
        /// <param name="e">The <see cref="SettingsEventArgs"/> passed to the event.</param>
        protected virtual void OnApplyingSettings(SettingsEventArgs e)
        {
            if (null != this.ApplyingSettings)
            {
                this.ApplyingSettings(this, e);
            }
        }

        #endregion

        #region page lifecycle

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Init"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
        protected override void OnInit(EventArgs e)
        {
            this.Page.RegisterJQueryUI();

            base.OnInit(e);
        }

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.PreRender"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            if (this.Visible)
            {
                var settings = SettingSerializer.FetchSettings(this);

                // handle theme wrapping
                // NOTE: This is somewhat of a hack due to lack of other options. Keep an eye on this, as it may break sooner rather than later!
                string themeName = this.ResolveThemeName();
                if (!String.IsNullOrEmpty(themeName))
                {
                    // NOTE: 'this' is the actual content control of the dialog, hence the need to get the parent's parent!
                    settings["open"] =
                        new ClientEventHandler(this.ClientEvents.OpenHandler ?? new ClientEventHandler("", ""),
                                               String.Format(CultureInfo.InvariantCulture,
                                                             "jQuery(this).parent().wrap('<div class=\"jquery-ui-{0}\" style=\"position: absolute\"></div>');jQuery('body>.ui-widget-overlay').wrap('<div class=\"jquery-ui-{0}\" style=\"position: absolute\"></div>');",
                                                             themeName));
                    settings["close"] =
                        new ClientEventHandler(this.ClientEvents.CloseHandler ?? new ClientEventHandler("", ""),
                                               "jQuery(this).parent().parent().replaceWith(jQuery(this).parent());jQuery('body>.ui-widget-overlay').parent().replaceWith(jQuery('body>.ui-widget-overlay'));");
                }

                // process Position to make it use the CustomPosition if applicable.
                if (this.Position == DialogPosition.Custom)
                {
                    if (null != this.CustomPosition)
                    {
                        settings["position"] = this.CustomPosition;
                    }
                    else
                    {
                        settings.Remove("position");
                    }
                }
                if (this.Height < 0)
                {
                    settings.Remove("height");
                }
                if (this.MaxHeight < 0)
                {
                    settings.Remove("maxHeight");
                }
                if (this.MaxWidth < 0)
                {
                    settings.Remove("maxWidth");
                }

                // apply custom setting manipulation logic
                this.OnApplyingSettings(new SettingsEventArgs(settings));

                // make it json and register the DocumentReadyBlock
                string settingsJson = SettingSerializer.Serialize(settings);
                this.Page.RegisterJQueryOnDocumentReadyBlock(
                    String.Format(
                        CultureInfo.InvariantCulture,
                        "$('#{0}').dialog({1})",
                        this.ClientID,
                        settingsJson
                        ));
            }
        }

        /// <summary>
        /// Renders the <see cref="Dialog"/> control to the specified <see cref="T:System.Web.UI.HtmlTextWriter"/> object.
        /// </summary>
        /// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> that receives the rendered output.</param>
        protected override void Render(HtmlTextWriter writer)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
            writer.RenderBeginTag(HtmlTextWriterTag.Div);

            base.Render(writer);

            writer.RenderEndTag();
        }

        #endregion

        #region methods

        private string ResolveThemeName()
        {
            string themeName = this.ThemeName;
            if (String.IsNullOrEmpty(themeName))
            {
                themeName = this.Page.GetDefaultJQueryUITheme();
            }
            return themeName;
        }

        #endregion
    }
}
